package modelo;

import java.awt.Color;
import java.util.ArrayList;
import java.util.List;

import javax.media.opengl.GL;

import controle.Util;

/**
 * Classe que representa um polígono(aberto ou fechado) contendo os seus pontos.
 * 
 * @author jean
 * @author diego
 */
public class Poligono extends ObjetoGrafico {

	private List<Ponto> pontos;
	private boolean aberto;
	private Ponto pontoSelecionado;

	/**
	 * Cria um Polígono
	 * 
	 * @param aberto
	 *            - true Se for aberto, false se for fechado
	 * @param cor
	 *            - a cor do polígono
	 */
	public Poligono(boolean aberto, Color cor) {
		super(cor);

		this.pontos = new ArrayList<Ponto>();
		this.aberto = aberto;
	}

	/**
	 * Retorna a lista de pontos
	 * 
	 * @return pontos - os pontos do polígono
	 */
	public List<Ponto> getPontos() {
		return pontos;
	}

	/**
	 * Adiciona um ponto no polígono
	 * 
	 * @param ponto
	 *            - o ponto
	 */
	public void addPonto(Ponto ponto) {
		pontos.add(ponto);
	}

	/**
	 * Remove o ponto do polígono
	 * 
	 * @param p
	 *            - o ponto para ser removido
	 */
	public void removePonto(Ponto p) {
		pontos.remove(p);
	}

	/**
	 * Atribui uma lista de pontos para o polígono
	 * 
	 * @param pontos
	 *            - a lista de pontos
	 */
	public void setPontos(List<Ponto> pontos) {
		this.pontos = pontos;
	}

	/**
	 * Retorna se o polígono é aberto ou fechado
	 * 
	 * @return true se for aberto, false se for fechado
	 */
	public boolean isAberto() {
		return aberto;
	}

	/**
	 * Atribui se o polígono é aberto ou fechado
	 * 
	 * @param aberto
	 *            - true Se for aberto, false se for fechado
	 */
	public void setAberto(boolean aberto) {
		this.aberto = aberto;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void desenhar(GL gl) {
		gl.glPushMatrix();
		gl.glMultMatrixd(getTransformacao().getDate(), 0);
		if (aberto) {
			gl.glBegin(GL.GL_LINE_STRIP);
		} else {
			gl.glBegin(GL.GL_LINE_LOOP);
		}
		gl.glColor3f(getCor().getRed(), getCor().getGreen(), getCor().getBlue());
		for (Ponto p : pontos) {
			getbBox().recalcularBBox(p);
			gl.glVertex2d(p.getX(), p.getY());
		}
		gl.glEnd();
		gl.glPopMatrix();
		gl.glFlush();
		destacarVertices(gl);
	}

	/**
	 * Método responsável por destacar cada vértice do polígono com um círculo.
	 * 
	 * @param gl
	 */
	private void destacarVertices(GL gl) {
		final double raio = 3;
		gl.glPushMatrix();
		gl.glMultMatrixd(getTransformacao().getDate(), 0);
		gl.glBegin(GL.GL_POINTS);
		gl.glColor3f(getCor().getRed(), getCor().getGreen(), getCor().getBlue());
		for (Ponto p : pontos) {
			double x = (float) Util.RetornaX((double) 0, raio) + p.getX();
			double y = (float) Util.RetornaY((double) 0, raio) + p.getY();

			gl.glVertex2d(x, y);

			double xTemp = 0;
			double yTemp = 0;

			for (int i = 5; i <= 360; i = i + 5) {
				x = Util.RetornaX((double) i, raio) + p.getX();
				y = Util.RetornaY((double) i, raio) + p.getY();
				xTemp = x;
				yTemp = y;
				gl.glVertex2d(x, y);
				gl.glVertex2d(xTemp, yTemp);
			}

			if (p == pontoSelecionado) {
				gl.glColor3f(0, 0, 0);
				destacarSelecionado(gl, 4, x, y, p);
				gl.glColor3f(255, 0, 0);
				destacarSelecionado(gl, 5, x, y, p);
			}

		}
		gl.glEnd();
		gl.glPopMatrix();
		gl.glFlush();
	}

	private void destacarSelecionado(GL gl, double raio, double x, double y,
			Ponto p) {
		double xTemp = 0;
		double yTemp = 0;
		for (int i = 5; i <= 360; i = i + 5) {
			x = Util.RetornaX((double) i, raio) + p.getX();
			y = Util.RetornaY((double) i, raio) + p.getY();
			xTemp = x;
			yTemp = y;
			gl.glVertex2d(x, y);
			gl.glVertex2d(xTemp, yTemp);
		}
	}

	/**
	 * Atribui um ponto do polígono selecionado
	 * 
	 * @param pontoSelecionado
	 *            - o ponto selecionado
	 */
	public void setPontoSelecionado(Ponto pontoSelecionado) {
		this.pontoSelecionado = pontoSelecionado;
	}

	/**
	 * Retorna ponto do polígono selecionado
	 * 
	 * @return o ponto Selecionado
	 */
	public Ponto getPontoSelecionado() {
		return this.pontoSelecionado;
	}
}
